﻿using System.IO;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using AutoMapper;
using ECommerce.Web.AutoMapper.ValueFormatters;
using ECommerce.Web.ControllerFactories;
using ECommerce.Web.Controllers;
using ECommerce.Web.Models;
using ECommerce.Web.NHibernate;
using ECommerce.Web.NHibernate.ConfigurationBuilders;
using ECommerce.Web.NHibernate.Sessions;
using ECommerce.Web.NHibernate.Sessions.Storage;
using ECommerce.Web.Validation;
using ECommerce.Web.ViewModels;
using FluentValidation;
using FluentValidation.Mvc;
using log4net.Config;
using MvcContrib.Routing;
using Spark.Web.Mvc;
using StructureMap;
using NHibernateCfg = NHibernate.Cfg;

namespace ECommerce.Web
{
    public static class Bootstrapper
    {
        public static void Configure()
        {
            string loggingConfigFilePath = HttpContext.Current.Server.MapPath("~/Log4Net.config");

            ConfigureLogging(loggingConfigFilePath);
            
            ConfigureServiceLocator();

            RegisterObjectMappings();

            RegisterAreas();

            RegisterRoutes(RouteTable.Routes);
            
            RegisterViewEngine(ViewEngines.Engines);

            ConfigureControllerFactory();

            ConfigureValidation();

            var configurationBuilder = new DefaultConfigurationBuilder();

            NHibernateCfg.Configuration configuration = configurationBuilder.Build(PersistenceOptions.Default());

            ConfigureSessionSource(configuration);
        }

        public static void ConfigureLogging(string loggingConfigFilePath)
        {
            XmlConfigurator.ConfigureAndWatch(new FileInfo(loggingConfigFilePath));
        }

        public static IContainer ConfigureServiceLocator()
        {
            ObjectFactory.Initialize( x => x.AddRegistry(new ECommerceRegistry()));

            return ObjectFactory.Container;
        }

        public static void RegisterObjectMappings()
        {
            Mapper.CreateMap<Basket, BasketView>()
                .ForMember(destination => destination.SubTotal, options => options.AddFormatter<CurrencyFormatter>());

            Mapper.CreateMap<BasketItem, BasketItemView>()
                .ForMember(destination => destination.ProductPrice, options => options.AddFormatter<CurrencyFormatter>());
        }

        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            MvcRoute.MappUrl("{controller}/{action}/{id}")
                .ToDefaultAction<HomeController>(x => x.Index(), new { id = 0 })
                .AddWithName("Default", routes);
        }

        public static void RegisterAreas()
        {
            AreaRegistration.RegisterAllAreas();
        }

        public static void RegisterViewEngine(ViewEngineCollection engines)
        {
            SparkEngineStarter.RegisterViewEngine(engines);
        }

        public static void ConfigureControllerFactory()
        {
            ControllerBuilder.Current.SetControllerFactory(new ServiceLocatorControllerFactory());
        }

        public static void ConfigureValidation()
        {
            var validatorFactory = new ServiceLocatorValidatorFactory();

            var modelValidatorProvider = new FluentValidationModelValidatorProvider(validatorFactory);

            ModelValidatorProviders.Providers.Add(modelValidatorProvider);

            DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;

            ValidatorOptions.ResourceProviderType = typeof(ValidationErrorMessageResource);

            DefaultModelBinder.ResourceClassKey = "ValidationErrorMessageResource";
        }

        public static void ConfigureSessionSource(NHibernateCfg.Configuration configuration)
        {
            SessionSource.Current.SetSessionFactory(configuration.BuildSessionFactory());
            SessionSource.Current.SetSessionStorage(new SimpleSessionStorage());
        }
    }
}
